#pragma once
#include <iostream>
#include <vector>
#include "sem.hpp"
#include "mutex.hpp"

namespace RingBufferModule
{
    using namespace MySemModule;
    using namespace LockModule;

    template <typename T>
    class RingBuffer
    {
    public:
        RingBuffer(int cap)
            : _cap(cap), _buffer(cap), _p_pos(0),
              _c_pos(0), _sem_data(0), _sem_space(cap)
        {
        }
        // 生产者
        void Equeue(const T &in)
        {
            _sem_space.p();
            LockGuard lock(_p_lock);

            _buffer[_p_pos] = in;
            _p_pos = (_p_pos + 1) % _cap;
            _sem_data.v();
        }

        // 消费者
        void dequeue(T *out)
        {
            _sem_data.p();
            LockGuard lock(_c_lock);

            *out = _buffer[_c_pos];
            _c_pos = (_c_pos + 1) % _cap;
            _sem_space.v();
        }
        ~RingBuffer() {}

    private:
        std::vector<T> _buffer;
        int _cap;

        int _p_pos; // 生产者位置
        int _c_pos; // 消费者位置

        Sem _sem_data;  // 数据信号量
        Sem _sem_space; // 空间信号量

        Mutex _p_lock; // 生产者锁
        Mutex _c_lock; // 消费者锁
    };
} // namespace MyRingBuffer
